import numpy as np
import random
from collections import defaultdict

class NeuralRegion:
    """神经区域的基类"""
    def __init__(self, name, size=100):
        self.name = name
        self.size = size
        self.activation = np.zeros(size)
        self.connections = {}
        self.threshold = 0.5
        self.decay_rate = 0.1
        
    def connect_to(self, target_region, weight=0.1):
        """建立与另一个区域的连接"""
        if target_region not in self.connections:
            self.connections[target_region] = weight
        
    def activate(self, pattern, strength=1.0):
        """激活这个区域的特定模式"""
        if len(pattern) != self.size:
            # 调整pattern大小以匹配区域大小
            if len(pattern) > self.size:
                pattern = pattern[:self.size]
            else:
                pattern = np.pad(pattern, (0, self.size - len(pattern)), 'constant')
        
        self.activation = np.maximum(self.activation, pattern * strength)
        # 返回自身，以便可以检查该区域是否被激活
        return True
    
    def propagate_activation(self):
        """传播激活到连接的区域"""
        activated_regions = []
        for target_region, weight in self.connections.items():
            if np.max(self.activation) > self.threshold:
                # 只有当前区域激活足够强时才传播
                target_pattern = self.activation * weight
                if target_region.activate(target_pattern, weight):
                    activated_regions.append(target_region)
        return activated_regions
    
    def decay(self):
        """激活随时间衰减"""
        self.activation *= (1 - self.decay_rate)
        
    def is_active(self):
        """判断区域是否被激活"""
        return np.max(self.activation) > self.threshold
    
    def get_activation_pattern(self):
        """获取当前激活模式"""
        return self.activation.copy()


class TypeARegion(NeuralRegion):
    """一级输入细胞区：接收外界刺激"""
    def __init__(self, name, sensor_type, size=100):
        super().__init__(name, size)
        self.sensor_type = sensor_type  # 如 "visual", "auditory", "touch" 等
    
    def receive_stimulus(self, stimulus):
        """接收外部刺激并激活"""
        # 将刺激转换为激活模式
        pattern = self._encode_stimulus(stimulus)
        # 先激活自身
        self.activate(pattern)
        # 然后传播激活
        return self.propagate_activation()
    
    def _encode_stimulus(self, stimulus):
        """将刺激编码为激活模式"""
        # 简化实现，实际应根据刺激类型有不同的编码方式
        if isinstance(stimulus, str):
            # 字符串刺激(如声音词汇)
            encoded = np.zeros(self.size)
            for i, char in enumerate(stimulus[:self.size]):
                encoded[i] = ord(char) / 255  # 归一化
            return encoded
        elif isinstance(stimulus, (list, np.ndarray)):
            # 已经是数值数组的刺激(如图像)
            return np.array(stimulus[:self.size])
        else:
            # 其他类型的刺激
            return np.ones(self.size) * 0.5


class TypeBRegion(NeuralRegion):
    """二级输入细胞区：处理初级感觉信息"""
    def __init__(self, name, feature_type, size=100):
        super().__init__(name, size)
        self.feature_type = feature_type  # 如 "shape", "color", "word" 等
        self.receptive_patterns = {}  # 存储能识别的模式
    
    def learn_pattern(self, pattern_name, pattern):
        """学习识别特定模式"""
        self.receptive_patterns[pattern_name] = pattern
    
    def activate(self, pattern, strength=1.0):
        """根据模式激活区域，会识别相似的已学习模式"""
        # 检查输入模式是否匹配任何已学习的模式
        matched_pattern = None
        highest_similarity = 0
        
        for name, stored_pattern in self.receptive_patterns.items():
            similarity = self._calculate_similarity(pattern, stored_pattern)
            if similarity > highest_similarity and similarity > 0.7:  # 相似度阈值
                highest_similarity = similarity
                matched_pattern = name
        
        if matched_pattern:
            # 如果匹配到已知模式，激活会更强
            activation_pattern = self.receptive_patterns[matched_pattern] * strength * 1.5
            super().activate(activation_pattern, strength)
            return True
        else:
            # 否则正常激活
            return super().activate(pattern, strength)
    
    def _calculate_similarity(self, pattern1, pattern2):
        """计算两个模式之间的相似度"""
        # 确保两个模式的形状相同
        min_size = min(len(pattern1), len(pattern2))
        pattern1 = pattern1[:min_size]
        pattern2 = pattern2[:min_size]
        return 1 - np.mean(np.abs(pattern1 - pattern2))


class TypeCRegion(NeuralRegion):
    """三级输入细胞区：由多个B类细胞区连接形成"""
    def __init__(self, name, size=100):
        super().__init__(name, size)
        self.source_regions = []  # 连接到这个C区域的B区域
        self.formation_threshold = 0.3  # 形成连接所需的最小激活阈值
        
    def connect_from(self, source_region, weight=0.2):
        """建立从B区域到这个C区域的连接"""
        if source_region not in self.source_regions:
            self.source_regions.append(source_region)
            source_region.connect_to(self, weight)
    
    def update_connections(self):
        """更新与源区域的连接强度"""
        for source in self.source_regions:
            if source.is_active() and self.is_active():
                # 如果源区域和当前区域同时激活，增强连接
                current_weight = source.connections.get(self, 0.1)
                source.connections[self] = min(current_weight + 0.05, 1.0)
    
    def create_compound_pattern(self, sources):
        """从多个源区域创建复合模式"""
        if len(sources) < 1:  # 修改为允许单个源
            return None
        
        # 检查所有源是否都激活了
        all_active = all(source.is_active() for source in sources)
        if not all_active:
            return None
        
        # 创建复合模式
        compound_pattern = np.zeros(self.size)
        for i, source in enumerate(sources):
            # 每个源区域的激活模式影响复合模式的不同部分
            if len(sources) > 1:
                section_size = self.size // len(sources)
                start = i * section_size
                end = min(start + section_size, self.size)  # 确保不超出数组边界
            else:
                # 如果只有一个源，则使用全部空间
                start = 0
                end = self.size
            
            source_pattern = source.get_activation_pattern()
            pattern_to_use = source_pattern[:end-start] if len(source_pattern) > (end-start) else source_pattern
            
            # 确保pattern_to_use的长度不超过目标区域
            if len(pattern_to_use) > 0:
                compound_pattern[start:start+len(pattern_to_use)] = pattern_to_use
        
        self.activate(compound_pattern)
        return compound_pattern


class TypeDRegion(NeuralRegion):
    """中间兴奋区：形成复杂概念和记忆"""
    def __init__(self, name, concept_type=None, size=100):
        super().__init__(name, size)
        self.concept_type = concept_type
        self.associated_regions = {}  # 与此区域相关的其他区域
        self.learning_rate = 0.2
        self.forgotten_rate = 0.01  # 记忆随时间消退的速率
    
    def associate(self, region, strength=0.1):
        """与另一个区域建立联想关系"""
        self.associated_regions[region] = strength
        region.connect_to(self, strength)
        
    def strengthen_association(self, region, amount=0.05):
        """增强与特定区域的联想强度"""
        if region in self.associated_regions:
            current_strength = self.associated_regions[region]
            self.associated_regions[region] = min(current_strength + amount, 1.0)
            
            # 更新region到self的连接强度
            if self in region.connections:
                region.connections[self] = self.associated_regions[region]
    
    def weaken_association(self, region, amount=0.02):
        """减弱与特定区域的联想强度"""
        if region in self.associated_regions:
            current_strength = self.associated_regions[region]
            self.associated_regions[region] = max(current_strength - amount, 0.0)
            
            if self.associated_regions[region] <= 0.01:
                # 如果联想强度太弱，移除联想
                del self.associated_regions[region]
                if self in region.connections:
                    del region.connections[self]
            else:
                # 更新region到self的连接强度
                if self in region.connections:
                    region.connections[self] = self.associated_regions[region]
    
    def update_all_associations(self):
        """更新所有联想的强度"""
        # 记忆衰退
        regions_to_remove = []
        for region, strength in self.associated_regions.items():
            new_strength = strength * (1 - self.forgotten_rate)
            if new_strength <= 0.01:
                regions_to_remove.append(region)
            else:
                self.associated_regions[region] = new_strength
                
        # 移除太弱的联想
        for region in regions_to_remove:
            del self.associated_regions[region]
            if self in region.connections:
                del region.connections[self]


class TypeERegion(NeuralRegion):
    """天生的兴奋区：先天固有反应"""
    def __init__(self, name, response_type, size=50):
        super().__init__(name, size)
        self.response_type = response_type  # 如 "pain", "pleasure", "hunger" 等
        self.activation_threshold = 0.4
        self.innate_response_strength = 0.8
    
    def trigger_innate_response(self):
        """触发天生的反应"""
        if self.is_active():
            # 根据反应类型生成特定的激活模式
            response_pattern = np.random.rand(self.size) * self.innate_response_strength
            self.activate(response_pattern, self.innate_response_strength)
            # 返回自身作为激活区域
            return [self]
        return []


class TypeFRegion(NeuralRegion):
    """天生调节兴奋区：影响其他区域的连接"""
    def __init__(self, name, regulation_type, size=50):
        super().__init__(name, size)
        self.regulation_type = regulation_type
        self.regulatory_strength = 0.5
        
    def regulate(self, source_region, target_region, effect="strengthen"):
        """调节两个区域之间的连接"""
        if not self.is_active():
            return []
            
        if effect == "strengthen":
            if target_region in source_region.connections:
                current_weight = source_region.connections[target_region]
                source_region.connections[target_region] = min(current_weight + self.regulatory_strength * 0.1, 1.0)
        elif effect == "weaken":
            if target_region in source_region.connections:
                current_weight = source_region.connections[target_region]
                source_region.connections[target_region] = max(current_weight - self.regulatory_strength * 0.1, 0.0)
        
        # 返回空列表而不是布尔值
        return []


class TypeGRegion(TypeFRegion):
    """后天调节兴奋区：后天形成的调节区"""
    def __init__(self, name, regulation_type, size=50):
        super().__init__(name, regulation_type, size)
        self.learning_threshold = 0.6
        self.formation_stage = 0  # 0-100，表示形成的程度
    
    def learn_regulation(self, source_region, target_region, effect_type, learning_rate=0.05):
        """学习调节特定的连接"""
        if self.is_active() and source_region.is_active() and target_region.is_active():
            self.formation_stage += learning_rate * 100
            if self.formation_stage >= 100:
                self.formation_stage = 100
                # 区域完全形成后能更有效地调节
                self.regulatory_strength = 0.8
            
            return self.regulate(source_region, target_region, effect_type)
        return []


class TypeHRegion(NeuralRegion):
    """输出细胞区：产生系统反应"""
    def __init__(self, name, action_type, size=50):
        super().__init__(name, size)
        self.action_type = action_type  # 如 "motor", "speech", "facial" 等
        self.action_threshold = 0.6
        self.action_patterns = {}  # 存储不同动作的激活模式
    
    def learn_action(self, action_name, pattern):
        """学习特定的动作模式"""
        self.action_patterns[action_name] = pattern
    
    def perform_action(self):
        """执行动作"""
        if not self.is_active() or np.max(self.activation) < self.action_threshold:
            return None
            
        # 找出最匹配的动作
        best_match = None
        highest_similarity = 0
        
        for action_name, pattern in self.action_patterns.items():
            similarity = self._calculate_similarity(self.activation, pattern)
            if similarity > highest_similarity:
                highest_similarity = similarity
                best_match = action_name
                
        return best_match if highest_similarity > 0.7 else "unrecognized_action"
    
    def _calculate_similarity(self, pattern1, pattern2):
        """计算两个模式之间的相似度"""
        return 1 - np.mean(np.abs(pattern1 - pattern2))


class ArtificialBrainModel:
    """整合所有区域的人工脑模型"""
    def __init__(self):
        self.regions = {}
        self.region_types = {
            'A': TypeARegion,
            'B': TypeBRegion,
            'C': TypeCRegion,
            'D': TypeDRegion,
            'E': TypeERegion,
            'F': TypeFRegion,
            'G': TypeGRegion,
            'H': TypeHRegion
        }
        
        # 初始化基本区域
        self._initialize_regions()
        
    def _initialize_regions(self):
        """初始化基本的脑区域"""
        # A类区域 - 感觉输入
        self.regions['A_visual'] = TypeARegion("Visual Input", "visual", size=200)
        self.regions['A_auditory'] = TypeARegion("Auditory Input", "auditory", size=200)
        self.regions['A_touch'] = TypeARegion("Touch Input", "touch", size=150)
        
        # B类区域 - 基本特征处理
        self.regions['B_shapes'] = TypeBRegion("Shape Recognition", "shape", size=150)
        self.regions['B_colors'] = TypeBRegion("Color Recognition", "color", size=100)
        self.regions['B_words'] = TypeBRegion("Word Recognition", "word", size=300)
        self.regions['B_touch_pain'] = TypeBRegion("Pain Sensation", "pain", size=80)
        
        # C类区域 - 综合特征
        self.regions['C_objects'] = TypeCRegion("Object Recognition", size=200)
        self.regions['C_phrases'] = TypeCRegion("Phrase Recognition", size=300)
        
        # D类区域 - 概念和记忆
        self.regions['D_knife_concept'] = TypeDRegion("Knife Concept", concept_type="object", size=150)
        self.regions['D_we_concept'] = TypeDRegion("We Concept", concept_type="pronoun", size=150)
        self.regions['D_group_concept'] = TypeDRegion("Group Concept", concept_type="social", size=150)
        
        # E类区域 - 天生反应
        self.regions['E_pain'] = TypeERegion("Pain Response", "pain", size=80)
        self.regions['E_pleasure'] = TypeERegion("Pleasure Response", "pleasure", size=80)
        
        # F类区域 - 天生调节
        self.regions['F_pain_withdraw'] = TypeFRegion("Pain Withdrawal", "protective", size=80)
        
        # G类区域 - 后天调节
        self.regions['G_knife_avoid'] = TypeGRegion("Knife Avoidance", "learned_caution", size=100)
        
        # H类区域 - 动作输出
        self.regions['H_hand_motor'] = TypeHRegion("Hand Movement", "motor", size=120)
        self.regions['H_speech'] = TypeHRegion("Speech Output", "verbal", size=200)
        
        # 建立基本连接
        self._setup_basic_connections()
        
    def _setup_basic_connections(self):
        """建立区域间的基本连接"""
        # A到B的连接
        self.regions['A_visual'].connect_to(self.regions['B_shapes'], 0.8)
        self.regions['A_visual'].connect_to(self.regions['B_colors'], 0.8)
        self.regions['A_auditory'].connect_to(self.regions['B_words'], 0.9)
        self.regions['A_touch'].connect_to(self.regions['B_touch_pain'], 0.9)
        
        # B到C的连接
        self.regions['B_shapes'].connect_to(self.regions['C_objects'], 0.7)
        self.regions['B_colors'].connect_to(self.regions['C_objects'], 0.5)
        self.regions['B_words'].connect_to(self.regions['C_phrases'], 0.8)
        
        # 其他连接可以动态建立
        
    def create_region(self, region_type, name, **kwargs):
        """创建新的区域"""
        if region_type in self.region_types:
            region_class = self.region_types[region_type]
            new_region = region_class(name, **kwargs)
            self.regions[name] = new_region
            return new_region
        return None
    
    def process_stimulus(self, stimulus_type, stimulus):
        """处理外部刺激"""
        activated_regions = []
        
        # 找到对应的A类区域
        if stimulus_type == "visual":
            activated_regions = self.regions['A_visual'].receive_stimulus(stimulus)
        elif stimulus_type == "auditory":
            activated_regions = self.regions['A_auditory'].receive_stimulus(stimulus)
        elif stimulus_type == "touch":
            activated_regions = self.regions['A_touch'].receive_stimulus(stimulus)
        else:
            print(f"未知的刺激类型: {stimulus_type}")
            return []
            
        # 记录所有激活的区域
        all_activated = []
        # 首先添加A类区域本身
        if stimulus_type == "visual" and self.regions['A_visual'].is_active():
            all_activated.append(self.regions['A_visual'])
        elif stimulus_type == "auditory" and self.regions['A_auditory'].is_active():
            all_activated.append(self.regions['A_auditory'])
        elif stimulus_type == "touch" and self.regions['A_touch'].is_active():
            all_activated.append(self.regions['A_touch'])
        
        # 添加通过传播激活的区域
        all_activated.extend(activated_regions)
        
        # 处理天生反应
        for name, region in self.regions.items():
            if isinstance(region, TypeERegion) and region.is_active():
                all_activated.extend(region.trigger_innate_response())
                
        # 处理调节作用
        for name, region in self.regions.items():
            if isinstance(region, TypeFRegion) and region.is_active():
                # 这里简化了，实际应该有更复杂的调节机制
                for source in self.regions.values():
                    for target in source.connections:
                        region.regulate(source, target)
                        
        # 返回所有激活的区域名称
        return [r.name for r in all_activated if r.is_active()]
    
    def update_all_regions(self):
        """更新所有区域的状态"""
        for region in self.regions.values():
            region.decay()
            if isinstance(region, TypeDRegion):
                region.update_all_associations()
    
    def get_active_concepts(self):
        """获取当前激活的概念"""
        active_concepts = []
        for name, region in self.regions.items():
            if isinstance(region, TypeDRegion) and region.is_active():
                active_concepts.append((name, np.max(region.activation)))
        return sorted(active_concepts, key=lambda x: x[1], reverse=True)
    
    def get_output_actions(self):
        """获取当前系统的输出动作"""
        actions = []
        for name, region in self.regions.items():
            if isinstance(region, TypeHRegion) and region.is_active():
                action = region.perform_action()
                if action:
                    actions.append((name, action))
        return actions


# 示例：演示如何使用这个模型
def demonstrate_knife_learning():
    """演示刀子学习的例子"""
    brain = ArtificialBrainModel()
    
    # 预先设置一些模式
    knife_visual = np.random.rand(200) * 0.5 + 0.5  # 假设这是刀的视觉模式
    knife_word = np.zeros(300)
    for i, char in enumerate("knife"):
        knife_word[i] = ord(char) / 255
    
    pain_pattern = np.random.rand(80) * 0.8 + 0.2  # 痛的感觉
    withdraw_pattern = np.random.rand(120) * 0.9  # 缩手的动作
    
    # 教会系统识别刀
    brain.regions['B_shapes'].learn_pattern("knife_shape", knife_visual[:150])
    brain.regions['B_words'].learn_pattern("knife_word", knife_word)
    brain.regions['H_hand_motor'].learn_action("withdraw_hand", withdraw_pattern)
    
    print("初始状态：看到刀子的反应")
    # 第一次看到刀子
    activated = brain.process_stimulus("visual", knife_visual)
    print(f"激活的区域: {activated}")
    print(f"当前概念: {brain.get_active_concepts()}")
    print(f"输出动作: {brain.get_output_actions()}")
    
    print("\n学习过程：摸刀子被割伤")
    # 摸刀子被割伤
    pain_stimulus = np.random.rand(150) * 0.7 + 0.3
    activated = brain.process_stimulus("touch", pain_stimulus)
    
    # E类区域痛感激活
    brain.regions['E_pain'].activate(pain_pattern)
    print(f"激活的区域: {activated}")
    
    # F类区域触发缩手反射
    brain.regions['F_pain_withdraw'].activate(np.random.rand(80) * 0.7 + 0.3)
    brain.regions['F_pain_withdraw'].regulate(
        brain.regions['E_pain'], 
        brain.regions['H_hand_motor'], 
        "strengthen"
    )
    
    # 手部执行缩手动作
    brain.regions['H_hand_motor'].activate(withdraw_pattern)
    print(f"输出动作: {brain.get_output_actions()}")
    
    # 形成D区记忆：刀子和痛的关联
    brain.regions['D_knife_concept'].activate(knife_visual[:150])
    brain.regions['D_knife_concept'].associate(brain.regions['E_pain'], 0.7)
    brain.regions['D_knife_concept'].associate(brain.regions['B_shapes'], 0.8)
    
    # 形成G区：看到刀子要避免
    brain.regions['G_knife_avoid'].activate(np.random.rand(100) * 0.6 + 0.4)
    brain.regions['G_knife_avoid'].learn_regulation(
        brain.regions['D_knife_concept'],
        brain.regions['H_hand_motor'],
        "strengthen",
        0.5
    )
    
    print("\n学习后：再次看到刀子的反应")
    # 再次看到刀子
    brain.update_all_regions()  # 重置所有区域
    activated = brain.process_stimulus("visual", knife_visual)
    
    # 由于已经建立了联系，D区刀子概念会激活
    # 这会通过G区的调节导致手部动作区域激活缩手动作
    print(f"激活的区域: {activated}")
    print(f"当前概念: {brain.get_active_concepts()}")
    print(f"输出动作: {brain.get_output_actions()}")


def demonstrate_language_learning():
    """演示语言学习的例子：'我们'概念的形成"""
    brain = ArtificialBrainModel()
    
    # 预先设置一些模式
    wo_word = np.zeros(300)  # "我"的声音
    for i, char in enumerate("我"):
        wo_word[i] = ord(char) / 255
        
    men_word = np.zeros(300)  # "们"的声音
    for i, char in enumerate("们"):
        men_word[i] = ord(char) / 255
    
    group_visual = np.random.rand(200) * 0.6 + 0.4  # 一群人的视觉
    
    # 教会系统识别基本词汇
    brain.regions['B_words'].learn_pattern("wo_word", wo_word)
    brain.regions['B_words'].learn_pattern("men_word", men_word)
    
    print("初始状态：听到'我'和'们'的分离反应")
    # 听到"我"
    activated = brain.process_stimulus("auditory", wo_word)
    print(f"听到'我'激活的区域: {activated}")
    print(f"当前概念: {brain.get_active_concepts()}")
    
    # 听到"们"
    activated = brain.process_stimulus("auditory", men_word)
    print(f"听到'们'激活的区域: {activated}")
    print(f"当前概念: {brain.get_active_concepts()}")
    
    print("\n学习过程：反复听到'我们'并看到群体")
    # 创建"我们"的C区域
    wo_men_pattern = np.zeros(300)
    # 将"我"和"们"的部分特征组合起来
    wo_men_pattern[:150] = wo_word[:150]
    wo_men_pattern[150:300] = men_word[:150]
    
    # 创建"我们"的C区域
    if 'C_wo_men' not in brain.regions:
        brain.regions['C_wo_men'] = TypeCRegion("我们组合词", size=300)
    
    # 反复学习过程
    for i in range(5):
        print(f"学习循环 {i+1}:")
        
        # 同时看到群体和听到"我们"
        print("  看到群体...")
        brain.process_stimulus("visual", group_visual)
        print("  听到'我们'...")
        brain.process_stimulus("auditory", wo_men_pattern)
        
        # 将"我"和"们"的B区域连接到"我们"的C区域
        brain.regions['C_wo_men'].connect_from(brain.regions['B_words'])
        
        # 使用单一源创建复合模式
        brain.regions['C_wo_men'].create_compound_pattern([
            brain.regions['B_words'] 
        ])
        
        # 将"我们"的C区域与群体的视觉D区域建立联系
        if 'D_group_concept' not in brain.regions:
            brain.regions['D_group_concept'] = TypeDRegion("群体概念", "social", size=150)
        
        brain.regions['D_group_concept'].activate(group_visual[:150])
        if 'C_wo_men' in brain.regions and brain.regions['C_wo_men'].is_active():
            brain.regions['D_group_concept'].associate(brain.regions['C_wo_men'], 0.2 * (i+1))
            print(f"  '我们'与群体概念的联系强度: {0.2 * (i+1):.2f}")
        
        # 输出当前活跃的概念
        active_concepts = brain.get_active_concepts()
        if active_concepts:
            print(f"  当前激活的概念: {active_concepts}")
        else:
            print("  当前没有激活的概念")
            
        # 逐渐增强连接
        brain.update_all_regions()
    
    print("\n学习后：听到'我们'的反应")
    # 重置系统状态
    for region in brain.regions.values():
        region.activation = np.zeros(region.size)
    
    # 听到"我们"
    activated = brain.process_stimulus("auditory", wo_men_pattern)
    print(f"激活的区域: {activated}")
    print(f"当前概念: {brain.get_active_concepts()}")
    
    # 验证只听到"我们"是否能激活群体概念
    if brain.regions['D_group_concept'].is_active():
        print("成功：仅听到'我们'就能激活群体概念！")
    else:
        print("学习不完全：仅听到'我们'还不能激活群体概念。")


if __name__ == "__main__":
    # 运行演示
    print("================ 刀子学习演示 ================")
    demonstrate_knife_learning()
    
    print("\n\n================ 语言学习演示 ================")
    demonstrate_language_learning() 